package view.visualizations;

import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.BorderFactory;

import prefuse.Display;
import prefuse.Visualization;
import prefuse.action.layout.AxisLayout;
import prefuse.controls.PanControl;
import prefuse.controls.ZoomControl;
import prefuse.controls.ZoomToFitControl;
import prefuse.data.expression.AndPredicate;
import prefuse.data.expression.Predicate;
import prefuse.data.query.RangeQueryBinding;
import prefuse.visual.VisualItem;
import prefuse.visual.VisualTable;
import prefuse.visual.sort.ItemSorter;
import data.DataManager;

public abstract class XCVis extends Visualization {
	
	protected Display display;
	private List<String> selectedNames;
	protected Predicate originalPredicate;
	VisualTable tupleSet;
	AxisLayout xAxis;
	AxisLayout yAxis;
	protected RangeQueryBinding dateQuery;
	protected RangeQueryBinding raceQuery; // this could all be a map or something, but...eh
	
	/**
	 * True only if the creation of this vis gets canceled while being instantiated.
	 */
	protected boolean canceled;
	
	public XCVis() {
		selectedNames = new ArrayList<String>();
		canceled = false;
		display = new Display(this);
		this.removeGroup("data");
		tupleSet = this.addTable("data", DataManager.getInstance().getTable());
		dateQuery = new RangeQueryBinding(this.getTupleSet(), "Date");
		raceQuery = new RangeQueryBinding(this.getTupleSet(), "Race");
		// this makes the data points display above the grid lines
		display.setItemSorter(new ItemSorter() {
			public int score(VisualItem item) {
				int score = super.score(item);
				
				if (item.isInGroup("data")) {
					score++;
					if (selectedNames.contains(item.get("Name"))) {
						score += 2;
					}
				}
				return score;
			}
		});
		display.setHighQuality(true);
		display.setSize(900, 768);
		display.setBorder(BorderFactory.createEmptyBorder(15, 30, 15, 30));
		display.addComponentListener(new ComponentAdapter() {
			public void componentResized(ComponentEvent e) {
				run("update");
			}
		});
		display.addControlListener(new PanControl());
		display.addControlListener(new ZoomControl());
		display.addControlListener(new ZoomToFitControl());
	}
	
	public abstract void setupVis();
	
	public void addSelectedName(final String name) {
		selectedNames.add(name);
	}
	
	public void removeSelectedName(final String name) {
		selectedNames.remove(name);
	}
	
	public void clearSelectedNames() {
		selectedNames.clear();
	}
	public List<String> getSelectedNames() {
		return selectedNames;
	}
	
	public void removeFilterAction() {
		this.removeGroup("data");
		addFilterAction(null);
		setupVis(); // there has to be a better way to do this.
	}
	
	public Display getDisplay() {
		return display;
	}
	
	public VisualTable getTupleSet() {
		return tupleSet;
	}
	
	public RangeQueryBinding getDateQuery() {
		return dateQuery;
	}
	
	public RangeQueryBinding getRaceQuery() {
		return raceQuery;
	}
	
	public AxisLayout getXAxis() {
		return xAxis;
	}
	
	public AxisLayout getYAxis() {
		return yAxis;
	}
	
	public boolean getIsCanceled() {
		return canceled;
	}
	
	public void addFilterAction(final Predicate p) {
		this.removeGroup("data");
		if (p==null && originalPredicate==null) {
			tupleSet = addTable("data", DataManager.getInstance().getTable());
		} else if (p==null) {
			tupleSet = addTable("data", DataManager.getInstance().getTable(), originalPredicate);
		} else if (originalPredicate==null) {
			tupleSet = addTable("data", DataManager.getInstance().getTable(), p);
		} else {
			Predicate finalPredicate = new AndPredicate(originalPredicate, p);
			tupleSet = addTable("data", DataManager.getInstance().getTable(), finalPredicate);
		}
		setupVis();
		
//		filterAction = new ActionList();
//		filterAction.add(action);
//		filterAction.add(new RepaintAction());
//		this.putAction("filter", filterAction);
//		this.run("filter");
	}
}
